package cn.px.service.purchase.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.px.dao.entity.purchase.*;
import cn.px.dao.enums.FormActionEnum;
import cn.px.dao.enums.MoneyTypeEnum;
import cn.px.dao.enums.PurchaseAuditNodeEnum;
import cn.px.dao.enums.PurchaseListStatusEnum;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import cn.px.common.bean.AbstractPageResultBean;
import cn.px.common.exception.BusinessException;
import cn.px.common.util.IdGeneratorUtils;
import cn.px.dao.bean.MyPage;
import cn.px.dao.config.aggregation.MyAggregateCondition;
import cn.px.dao.dto.purchase.PurchaseListDTO;
import cn.px.dao.dto.purchase.PurchaseOrderDTO;
import cn.px.dao.dto.store.SpareStoreDTO;
import cn.px.dao.mapper.purchase.PurchaseApplyMapper;
import cn.px.dao.mapper.purchase.PurchaseListMapper;
import cn.px.dao.mapper.purchase.PurchaseOrderMapper;
import cn.px.dao.mapper.purchase.SupplierMapper;
import cn.px.dao.mapper.store.SpareStoreMapper;
import cn.px.dao.util.CustomExcelImportUtil;
import cn.px.dao.vo.query.purchase.PurchaseListVO;
import cn.px.dao.vo.query.store.SpareStoreVO;
import cn.px.service.base.impl.BaseServiceImpl;
import cn.px.service.purchase.PurchaseListService;
import cn.px.service.util.DataField;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.additional.aggregation.AggregateType;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description 采购明细 service 实现类
 * @author 品讯科技
 * @date 2024-08
 * @Version Copyright (c) 2020,北京乾元坤和科技有限公司 All rights reserved.
 */
@AllArgsConstructor
@Service("purchaseListService")
public class PurchaseListServiceImpl extends BaseServiceImpl<PurchaseListMapper, PurchaseList, PurchaseListDTO> implements PurchaseListService {

    private final PurchaseApplyMapper purchaseApplyMapper;

    private final PurchaseOrderMapper purchaseOrderMapper;

    private final SupplierMapper supplierMapper;
    private final SpareStoreMapper spareStoreMapper;

    @Override
    public int batchDelete(List<String> ids) {
        Weekend<PurchaseList> weekend = new Weekend<>(PurchaseList.class);
        WeekendCriteria<PurchaseList, Object> weekendCriteria = weekend.weekendCriteria();
        weekendCriteria.andIn(PurchaseList::getId, ids);
        mapper.deleteByExample(weekend);
        return 1;
    }

    @Override
    public AbstractPageResultBean<PurchaseListVO> selectPageList(PurchaseListDTO record, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        AbstractPageResultBean<PurchaseListVO> result = new MyPage(mapper.selectList(record));
        List<PurchaseListVO> list = result.getRows();
        String applyId = record.getPurchaseApplyId();
        String orderId = record.getPurchaseOrderId();
        String projectId = null;
        if (!StringUtils.isEmpty(applyId) && !"-1".equals(applyId)) {
            PurchaseApply apply = purchaseApplyMapper.selectByPrimaryKey(applyId);
            projectId = apply.getProjectId();
        }
        if (!StringUtils.isEmpty(orderId) && !"-1".equals(orderId)) {
            PurchaseOrder order = purchaseOrderMapper.selectByPrimaryKey(orderId);
            projectId = order.getProjectId();
        }
        if (!StringUtils.isEmpty(orderId) && CollectionUtil.isNotEmpty(list)) {
            List<String> spareList = list.stream().map(item -> item.getGoodsId()).collect(Collectors.toList());
            SpareStoreDTO query = new SpareStoreDTO();
            query.setStoreIdList(spareList);
            query.setUseProject(projectId);
            List<SpareStoreVO> spares = spareStoreMapper.selectTotalStock(query);
            Map<String, BigDecimal> map = new HashMap<>();
            if (CollectionUtil.isNotEmpty(spares)) {
                spares.forEach(item -> map.put(item.getSpareId(), item.getNum()));
            }
            list.forEach(item -> {
                String spareId = item.getGoodsId();
                BigDecimal num = map.get(spareId);
                if (num == null) {
                    item.setStoreQuantity(BigDecimal.ZERO);
                } else {
                    item.setStoreQuantity(num);
                }
            });

        }
        return result;
    }

    @Override
    public AbstractPageResultBean<PurchaseList> selectPageInfo(PurchaseListDTO record, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return new MyPage(mapper.selectList(record));
    }

    @Override
    public PurchaseList saveModelByDTO(PurchaseListDTO model) {
        otherAttr(model);
        return super.saveModelByDTO(model);
    }

    @Override
    public void modModelByDTO(PurchaseListDTO model) {
        otherAttr(model);
        super.modModelByDTO(model);
    }

    /**
     * 添加其他属性
     *
     * @param model
     */
    private void otherAttr(PurchaseListDTO model) {
        PurchaseApply apply = purchaseApplyMapper.selectByPrimaryKey(model.getPurchaseApplyId());
        if (apply != null) {
            model.setDemandPlanId(apply.getDemandPlanId());
            model.setPurchasePlanId(apply.getPurchasePlanId());
        }
        String supplierId = model.getSupplierId();
        if (!StringUtils.isEmpty(supplierId)) {
            Supplier supplier = supplierMapper.selectByPrimaryKey(supplierId);
            if (supplier != null) {
                model.setSupplierName(supplier.getName());
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdateChoose(PurchaseListDTO record) {
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleListByOrder(PurchaseOrder order, List<Object> objects, Integer action) {
        if (CollectionUtils.isEmpty(objects)) {
            return;
        }
        if (FormActionEnum.DELETE.getValue().equals(action)) {
            String mainOrderId = purchaseOrderMapper.selectByPrimaryKey(order.getId()).getMainOrderId();
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                listDTO.setPurchaseOrderId(mainOrderId);
                otherAttr(order, listDTO, PurchaseListStatusEnum.PURCHASE_LIST_STATUS_ORDER.getValue());
            }
        }
        if (FormActionEnum.ADD.getValue().equals(action)) {
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                listDTO.setPurchaseOrderId(order.getId());
                otherAttr(order, listDTO, PurchaseListStatusEnum.PURCHASE_LIST_STATUS_ORDER.getValue());
            }
            return;
        }
        if (FormActionEnum.UPDATE.getValue().equals(action)) {
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                listDTO.setPurchaseOrderId(order.getId());
                otherAttr(order, listDTO, PurchaseListStatusEnum.PURCHASE_LIST_STATUS_ORDER.getValue());
            }
            return;
        }

    }

    /**
     * 添加其他属性
     *
     * @param model
     */
    private void otherAttr(PurchaseOrder order, PurchaseListDTO model, Integer status) {
        PurchaseListDTO update = new PurchaseListDTO();
        update.setId(model.getId());
        update.setPurchaseOrderId(model.getPurchaseOrderId());
        update.setPurchaseOrderNo(order.getBillNo());
        update.setMoneyType(order.getMoneyType());
        update.setExchangeRate(order.getExchangeRate());
        update.setStatus(status);
        super.modModelByDTO(update);
    }

    @Override
    public void handleListByApplyForOrder(PurchaseOrder order) {
        Weekend<PurchaseList> weekend = new Weekend<>(PurchaseList.class);
        WeekendCriteria<PurchaseList, Object> weekendCriteria = weekend.weekendCriteria();
        weekendCriteria.andEqualTo(PurchaseList::getPurchaseApplyId, order.getPurchaseApplyId());
        PurchaseList update = new PurchaseList();
        update.setPurchaseOrderId(order.getId());
        update.setMoneyType(order.getMoneyType());
        update.setExchangeRate(order.getExchangeRate());
        update.setStatus(PurchaseListStatusEnum.PURCHASE_LIST_STATUS_ORDER.getValue());
        mapper.updateByExampleSelective(update, weekend);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleListByEnquiry(PurchaseOrderDTO record) {
        PurchaseOrder order = purchaseOrderMapper.selectByPrimaryKey(record.getId());
        boolean flag = MoneyTypeEnum.MY.getValue().equals(order.getMoneyType());
        List<Object> objects = record.getUpdateList();
        for (int i = objects.size() - 1; i >= 0; i--) {
            PurchaseListDTO listDTO = convert(objects.get(i));
            PurchaseListDTO update = new PurchaseListDTO();
            update.setId(listDTO.getId());
            update.setMoneyType(record.getMoneyType());
            update.setExchangeRate(record.getExchangeRate());
            update.setAccountTotalMoney(calMoney(listDTO.getSupplyTotalMoney(), record.getExchangeRate(), flag));
            update.setAccountPrice(calMoney(listDTO.getSupplyPrice(), record.getExchangeRate(), flag));
            update.setSupplierId(listDTO.getSupplierId());
            update.setSupplierName(listDTO.getSupplierName());
            update.setSupplyPrice(listDTO.getSupplyPrice());
            update.setSupplyTotalMoney(listDTO.getSupplyTotalMoney());
            super.modModelByDTO(update);
        }
        return;
    }

    /**
     * 类型转换
     *
     * @param obj
     * @return
     */
    private PurchaseListDTO convert(Object obj) {
        return JSON.parseObject(JSON.toJSONString(obj), PurchaseListDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleListByApply(PurchaseApply apply, List<Object> objects, Integer action) {
        if (CollectionUtils.isEmpty(objects)) {
            return;
        }
        if (FormActionEnum.DELETE.getValue().equals(action)) {
            List<String> ids = objects.stream().map(item -> {
                PurchaseListDTO listDTO = convert(item);
                return listDTO.getId();
            }).collect(Collectors.toList());
            batchDelete(ids);
        }
        if (FormActionEnum.ADD.getValue().equals(action)) {
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                otherAttr(apply, listDTO);
                listDTO.setId(IdGeneratorUtils.getObjectId());
                listDTO.setDollarExchangeRate(apply.getDollarExchangeRate());
//                listDTO.setAccountExchangeRate(apply.getAccountExchangeRate());
                super.saveModelByDTO(listDTO);
            }
            return;
        }
        if (FormActionEnum.UPDATE.getValue().equals(action)) {
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                otherAttr(apply, listDTO);
                super.modModelByDTO(listDTO);
            }
            return;
        }


    }

    /**
     * 添加其他属性
     *
     * @param model
     */
    private void otherAttr(PurchaseApply apply, PurchaseListDTO model) {
        model.setDemandPlanId(apply.getDemandPlanId());
        model.setPurchasePlanId(apply.getPurchasePlanId());
        model.setPurchaseApplyId(apply.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleListByContractMainList(PurchaseContractMainList mainList, List<Object> objects, Integer action) {
        if (CollectionUtils.isEmpty(objects)) {
            return;
        }
        if (FormActionEnum.DELETE.getValue().equals(action)) {
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                otherAttr(mainList, listDTO, PurchaseListStatusEnum.PURCHASE_LIST_STATUS_ORDER.getValue());
            }
        }
        if (FormActionEnum.ADD.getValue().equals(action)) {
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                if ("-1".equals(listDTO.getGoodsId())) {
                    otherAttrForAdd(mainList, listDTO, PurchaseListStatusEnum.PURCHASE_LIST_STATUS_CONTRACT.getValue());
                } else {
                    otherAttr(mainList, listDTO, PurchaseListStatusEnum.PURCHASE_LIST_STATUS_CONTRACT.getValue());
                }
            }
            return;
        }
        if (FormActionEnum.UPDATE.getValue().equals(action)) {
            for (int i = objects.size() - 1; i >= 0; i--) {
                PurchaseListDTO listDTO = convert(objects.get(i));
                otherAttr(mainList, listDTO, PurchaseListStatusEnum.PURCHASE_LIST_STATUS_CONTRACT.getValue());
            }
            return;
        }

    }

    /**
     * 添加其他属性
     *
     * @param model
     */
    private void otherAttr(PurchaseContractMainList mainList, PurchaseListDTO model, Integer status) {
        PurchaseListDTO update = new PurchaseListDTO();
        update.setId(model.getId());
        update.setContractId(mainList.getContractId());
        update.setContractMainListId(mainList.getId());
        update.setStatus(status);
        super.modModelByDTO(update);
    }

    /**
     * 添加其他属性
     *
     * @param model
     */
    private void otherAttrForAdd(PurchaseContractMainList mainList, PurchaseListDTO model, Integer status) {
        model.setId(IdGeneratorUtils.getObjectId());
        model.setPurchaseOrderId(mainList.getPurchaseOrderId());
        model.setParentGoodsId(mainList.getGoodsId());
        model.setContractId(mainList.getContractId());
        model.setContractMainListId(mainList.getId());
        model.setStatus(status);
        model.setPrice(BigDecimal.ZERO);
        model.setSupplyPrice(BigDecimal.ZERO);
        model.setTotalMoney(BigDecimal.ZERO);
        model.setSupplyTotalMoney(BigDecimal.ZERO);
        model.setAccountPrice(BigDecimal.ZERO);
        model.setAccountTotalMoney(BigDecimal.ZERO);
        model.setMoneyType(mainList.getMoneyType());
        model.setExchangeRate(mainList.getExchangeRate());
        model.setAccountPrice(BigDecimal.ZERO);
        super.saveModelByDTO(model);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateArrivedQuantity(PurchaseOrder order, List<PurchaseList> list) {
        // 更新已到 零星采购一次入库
        list.forEach(item -> {
            PurchaseList elem = new PurchaseList();
            elem.setId(item.getId());
            elem.setArrivedQuantity(item.getArrivedQuantity());
            mapper.updateByPrimaryKeySelective(elem);
        });
    }

    @Override
    public List<PurchaseListVO> selectListHaveStoreNum(PurchaseListDTO record) {
        List<PurchaseListVO> result = mapper.selectList(record);
        if (CollectionUtil.isNotEmpty(result)) {
            List<String> spareList = result.stream().map(item -> item.getGoodsId()).collect(Collectors.toList());
            PurchaseApply apply = purchaseApplyMapper.selectByPrimaryKey(record.getPurchaseApplyId());
            Integer auditNode = apply.getAuditNode() / 10 * 10;
            SpareStoreDTO query = new SpareStoreDTO();
            query.setStoreIdList(spareList);
            if (PurchaseAuditNodeEnum.PROJECT.getValue().equals(auditNode) || PurchaseAuditNodeEnum.PROJECT_MANAGER.getValue().equals(auditNode)) {
                query.setUseProject(apply.getProjectId());
            } else if (PurchaseAuditNodeEnum.COMPANY.getValue().equals(auditNode)) {
                query.setUseCompany(apply.getCompanyId());
            }
            List<SpareStoreVO> spares = spareStoreMapper.selectTotalStock(query);
            Map<String, BigDecimal> map = new HashMap<>();
            if (CollectionUtil.isNotEmpty(spares)) {
                spares.forEach(item -> map.put(item.getSpareId(), item.getNum()));
            }
            result.forEach(item -> {
                String spareId = item.getGoodsId();
                BigDecimal num = map.get(spareId);
                if (num == null) {
                    item.setStoreQuantity(BigDecimal.ZERO);
                } else {
                    item.setStoreQuantity(num);
                }
            });

        }
        return result;
    }

    @Override
    public List<PurchaseList> getSupplierAndMoneyByOrder(String orderId) {
        Weekend<PurchaseList> weekend = new Weekend<>(PurchaseList.class);
        MyAggregateCondition condition = MyAggregateCondition.builder();
        WeekendCriteria<PurchaseList, Object> weekendCriteria = weekend.weekendCriteria();
        weekendCriteria.andEqualTo(PurchaseList::getPurchaseOrderId, orderId);
        condition.addAggregateProperty(DataField.fnToFieldName(PurchaseList::getSupplyTotalMoney), AggregateType.SUM);
        condition.groupBy("supplierId", "supplierName", "moneyType", "exchangeRate");
        List<PurchaseList> sumList = mapper.selectAggregationByExample(weekend, condition);
        if (CollectionUtil.isNotEmpty(sumList) && sumList.get(0) != null) {
            return sumList;
        }
        return new ArrayList<>();
    }

    @Override
    public void deleteByApply(String applyId) {
        Weekend<PurchaseList> weekend = new Weekend<>(PurchaseList.class);
        WeekendCriteria<PurchaseList, Object> weekendCriteria = weekend.weekendCriteria();
        weekendCriteria.andEqualTo(PurchaseList::getPurchaseApplyId, applyId);
        mapper.deleteByExample(weekend);
    }

    @Override
    public void importListForEnquiry(MultipartFile file, String purchaseOrderId, final Integer moneyType, final BigDecimal exchangeRate) {
        List<PurchaseListVO> list = mapper.selectList(new PurchaseListDTO().setPurchaseOrderId(purchaseOrderId));
        if (!CollectionUtils.isEmpty(list)) {
            Map<String, PurchaseListVO> listMap = new HashMap<>();
            list.forEach(item -> listMap.put(item.getNo(), item));
            try {
                List<PurchaseList> result = CustomExcelImportUtil.importPurchaseListForEnquiry(file.getInputStream());
                if (!CollectionUtils.isEmpty(result)) {
                    List<String> supplierNames = result.stream().map(item -> item.getSupplierName()).collect(Collectors.toList());
                    Weekend<Supplier> weekend = new Weekend<>(Supplier.class);
                    WeekendCriteria<Supplier, Object> weekendCriteria = weekend.weekendCriteria();
                    weekendCriteria.andIn(Supplier::getName, supplierNames);
                    List<Supplier> suppliers = supplierMapper.selectByExample(weekend);
                    Map<String, String> supplierMap = new HashMap<>();
                    suppliers.forEach(item -> supplierMap.put(item.getName(), item.getId()));
                    boolean flag = MoneyTypeEnum.MY.getValue().equals(moneyType);
                    result.forEach(item -> {
                        PurchaseList update = new PurchaseList();
                        PurchaseListVO vo = listMap.get(item.getNo());
                        if (vo == null) {
                            throw new BusinessException("采购单明细中没有该编号：" + item.getNo());
                        }
                        update.setId(vo.getId());
                        String supplierId = supplierMap.get(item.getSupplierName());
                        if (StringUtils.isEmpty(supplierId)) {
                            throw new BusinessException("供应商中没有该：" + item.getSupplierName());
                        }
                        update.setSupplierName(item.getSupplierName());
                        update.setSupplierId(supplierId);
                        update.setSupplyPrice(item.getSupplyPrice());
                        update.setSupplyTotalMoney(item.getSupplyTotalMoney());
                        update.setMoneyType(moneyType);
                        update.setExchangeRate(exchangeRate);
                        update.setAccountTotalMoney(calMoney(item.getSupplyTotalMoney(), exchangeRate, flag));
                        update.setAccountPrice(calMoney(item.getSupplyPrice(), exchangeRate, flag));
                        mapper.updateByPrimaryKeySelective(update);

                    });
                }
            } catch (Exception e) {
                throw new BusinessException(e.getMessage());
            }
        }
    }
}
